using DataAnalyticsTools.Models;
using MathNet.Numerics.Statistics;
using System;
using System.Collections.Generic;
using System.Linq;

namespace DataAnalyticsTools.Core.AnomalyPointDetect
{
    /// <summary>
    /// Z-Score异常检测器
    /// 通过计算数据点与均值的标准差距离来识别异常
    /// 适用于近似正态分布的时间序列数据
    /// </summary>
    public static class ZScoreDetector
    {
        /// <summary>
        /// 使用Z-score方法检测时间序列中的异常点
        /// </summary>
        /// <param name="data">时间序列数据（一维数组）</param>
        /// <param name="threshold">Z-score阈值，默认2.5，超过此值被认为是异常</param>
        /// <returns>异常检测结果</returns>
        /// <example>
        /// 输入:
        ///   data = [10, 11, 10.5, 10.2, 50, 10.3, 10.1]  // 50是异常点
        ///   threshold = 2.5
        /// 输出:
        ///   AnomalyScores = [0.5, 0.6, 0.3, 0.2, 5.2, 0.4, 0.1]
        ///   AnomalyPoints = [Index: 4, Value: 50]  // 索引4（值50）被识别为异常
        /// </example>
        public static AnomalyInfo Detect(
            float[] data,
            float threshold = 2.5f)
        {
            if (data == null || data.Length == 0)
            {
                return new AnomalyInfo
                {
                    Method = "ZScore",
                    AnomalyScores = Array.Empty<float>(),
                    Threshold = threshold,
                    AnomalyPoints = new List<AnomalyPoint>(),
                    BaselineValues = Array.Empty<float>(),
                    UpperBounds = Array.Empty<float>(),
                    LowerBounds = Array.Empty<float>()
                };
            }

            int n = data.Length;
            var scores = new float[n];

            // 计算均值和标准差
            var doubleData = data.Select(x => (double)x).ToArray();
            var mean = doubleData.Average();
            var std = doubleData.StandardDeviation();

            // 标准差为0，说明所有值相同，没有异常
            if (std == 0)
            {
                return new AnomalyInfo
                {
                    Method = "ZScore",
                    AnomalyScores = scores,
                    Threshold = threshold,
                    AnomalyPoints = new List<AnomalyPoint>(),
                    BaselineValues = Enumerable.Repeat((float)mean, n).ToArray(),
                    UpperBounds = Enumerable.Repeat((float)mean, n).ToArray(),
                    LowerBounds = Enumerable.Repeat((float)mean, n).ToArray()
                };
            }

            // 计算每个点的Z-score
            for (int i = 0; i < n; i++)
            {
                var zScore = Math.Abs((data[i] - mean) / std);
                scores[i] = (float)zScore;
            }

            // 计算边界
            var baselineValues = Enumerable.Repeat((float)mean, n).ToArray();
            var upperBounds = Enumerable.Repeat((float)(mean + threshold * std), n).ToArray();
            var lowerBounds = Enumerable.Repeat((float)(mean - threshold * std), n).ToArray();

            // 识别异常点
            var anomalyPoints = new List<AnomalyPoint>();
            for (int i = 0; i < n; i++)
            {
                if (scores[i] > threshold)
                {
                    var anomalyType = data[i] > mean ? AnomalyType.High : AnomalyType.Low;
                    anomalyPoints.Add(new AnomalyPoint
                    {
                        Index = i,
                        Value = data[i],
                        Score = scores[i],
                        Type = anomalyType,
                        Deviation = scores[i],
                        Reason = $"值 {data[i]:F2} 的Z-score为 {scores[i]:F2}，显著偏离均值 {mean:F2}"
                    });
                }
            }

            // 计算总体严重程度和置信度
            var severity = anomalyPoints.Any() ? anomalyPoints.Max(p => p.Score) : 0f;

            // 置信度基于样本量和分布稳定性
            // 1. 样本量因子：样本越多越可靠 (最大到30个样本时达到1.0)
            float sampleFactor = Math.Min(1.0f, n / 30.0f);

            // 2. 稳定性因子：变异系数越小越稳定 (CV < 0.5时置信度较高)
            float cv = (float)(std / (Math.Abs(mean) + 1e-6));
            float stabilityFactor = cv < 0.5f ? 1.0f - cv : 0.5f / (cv + 0.1f);

            // 综合置信度 = 样本量因子 * 稳定性因子
            var confidence = sampleFactor * stabilityFactor;

            return new AnomalyInfo
            {
                Method = "ZScore",
                AnomalyScores = scores,
                Threshold = threshold,
                AnomalyPoints = anomalyPoints,
                Severity = severity,
                Confidence = confidence,
                BaselineValues = baselineValues,
                UpperBounds = upperBounds,
                LowerBounds = lowerBounds
            };
        }
    }
}
